// -*-mode:c++; coding:utf-8-*-

#ifndef _XBASE_SESSION_MANAGER_HPP_
#define _XBASE_SESSION_MANAGER_HPP_

#include "session.hpp"

namespace xbase
{
	class session_manager
		: public async_module_base<io_service_pool::xbase_level, io_service_pool::xbase_level>
	{
	public:
		typedef async_module_base<io_service_pool::xbase_level, io_service_pool::xbase_level> base_type;
		typedef session_manager this_type;
		typedef boost::intrusive_ptr<this_type> ptr_type;

		typedef session session_type;
		typedef session_type::ptr_type session_ptr;
		typedef session_type::socket_type socket_type;
		typedef socket_type::endpoint_type endpoint_type;

		typedef boost::system::error_code error_code;

		typedef std::map<endpoint_type, session_ptr> map_type;

		typedef boost::function<void(session_ptr, const error_code&)> handler_type;

		typedef std::list<handler_type> handler_list;
		typedef std::map<endpoint_type, handler_list> request_map_type;

	public:
		session_manager(io_service_pool &pool)
			: base_type(pool, "session_manager")
			, m_io_service_pool(pool) {}

		// 工厂方法
		//
		// 连接建立后，会用创建的连接及错误码调用handler
		void async_connect(const endpoint_type &endpoint, handler_type handler);

		void close();

	protected:

		// 
		// 在lower_level中执行的方法
		//

		void on_session_closed(endpoint_type endpoint);

		void on_session_connected(endpoint_type ep,
					  session_ptr ptr,
					  const error_code &ec);

		void active_connect(const endpoint_type &endpoint) {
			// create new session on given endpoint
			session_ptr ptr(new_async_module(session_type, m_io_service_pool));
			ptr->socket().async_connect(endpoint,
						    this->get_lower_level_service().wrap(boost::bind(&this_type::on_session_connected,
												     this_ptr(),
												     endpoint,
												     ptr,
												     _1)));
		}

		// 不需要ptr_type持有
		this_type *this_ptr() {
			return this;
		}

	private:
		io_service_pool &m_io_service_pool;

		boost::mutex m_mutex;
		request_map_type m_requests;
		map_type m_sessions_connected;
	};

	typedef session_manager::ptr_type session_manager_ptr;

} // namespace xbase

#endif	// _XBASE_SESSION_MANAGER_HPP_
